<!--
 * @message: 表格组件
-->
<template>
  <!-- table公共组件：现已集成常用的删除、修改、查看按钮及分页组件,其余按钮由后端权限及前端publicBtn控制渲染 -->
  <div class="table">
    <Table
      ref="table"
      :border="border"
      :columns="columns"
      :data="dataSource"
      :size="size"
      :loading="loading"
      :width="width"
      :stripe="stripe"
      :show-header="showHeader"
      :height="height"
      @on-selection-change="handleSelectionChange"
      :max-height="maxHeight">
      <!-- 按钮具名 -->
      <template slot-scope="{ row, index }" slot="action">
        <Button
          v-if="selectBtn"
          type="text"
          size="small"
          style="color: #0F74FD"
          @click="handleView(row)"
        >查看</Button>
        <Button
          type="text"
          size="small"
          v-if="updateBtnExtraParam ? row[updateBtnExtraParam] !== updateBtnExtraVal && updateBtn : updateBtn"
          style="color: #0F74FD"
          @click="handleUpdate(row)"
        >修改</Button>
        <Button
          type="text"
          style="color: #FE4900;margin: 0"
          size="small"
          v-if="deleteBtn"
          @click="handleRemove(row, index)"
        >删除</Button>
        <Button
          v-for="(item, index) in otherBtnAuthList"
          :type="item.type ? item.type : 'text'"
          :size="item.size ? item.size : 'small'"
          :key="index + 'base-table-other-btn'"
          :style="item.style ? item.style : ''"
          @click="handleExpand((item.value || 'error'), row)"
        >{{item.label || item.value || 'error'}}</Button>
      </template>
      <!-- 开关具名 -->
      <template slot-scope="{ row }" slot="status">
        <i-switch
          size="large"
          v-if="stateBtn"
          :true-value="1"
          :false-value="0"
          @on-change="onChange($event, row)"
          v-model="row[statusField]"
          :before-change="handleBeforeChange"
        >
          <span slot="open">开启</span>
          <span slot="close">关闭</span>
        </i-switch>
        <Tag
          v-else
          :color="row[statusField] === 1 ? 'success' : 'error'"
          v-text="row[statusField] === 1 ? '是' : '否'"/>
      </template>
      <!-- 下拉具名 -->
      <template slot-scope="{ row }" slot="drop">
        <template v-if="typeOf(row[dropField]) !== 'undefined'">
          <Dropdown @on-click="handleClickDrop($event, row)" :transfer="true">
            <a href="javascript:void(0)">
              <span v-text="selectList[row[dropField]]"></span>
              <Icon type="ios-arrow-down"></Icon>
            </a>
            <DropdownMenu slot="list">
              <template v-for="(item, index) in selectList">
                <DropdownItem  v-if="item !== ''" :key="index" :name="index" v-text="item"></DropdownItem>
              </template>
            </DropdownMenu>
          </Dropdown>
        </template>
      </template>
    </Table>
    <!-- 分页组件 -->
    <Page
      v-if="isShowPage&&total>0"
      :total="total"
      :current.sync="current"
      :show-elevator="showElevator"
      :show-sizer="showSizer"
      :transfer="true"
      :show-total="showTotal"
      class-name="page"
      :disabled ="isDisabled "
      @on-change="handleChange"
      @on-page-size-change="handelSizeChange"
    />
  </div>
</template>

<script>
import message from '../../utils/message'
import { typeOf } from '../../utils/verification'
import { deleteTableByPk, getTableData } from '../../api/modules/table'
export default {
  name: 'BaseTable',
  props: {
    // 表格列的配置描述（必传）
    columns: {
      type: Array,
      require: true
    },
    // 请求地址(表格)
    action: {
      type: String,
      default: ''
    },
    // 表格尺寸
    size: {
      type: String,
      default: 'default'
    },
    // 是否显示间隔斑马纹
    stripe: {
      type: Boolean,
      default: false
    },
    // 是否显示纵向边框
    border: {
      type: Boolean,
      default: false
    },
    // 表格宽度
    width: {
      type: [String, Number],
      default: 'auto'
    },
    // 表格高度
    height: {
      type: [String, Number],
      default: ''
    },
    // 表格最大高度（固定表格表头时使用）
    maxHeight: {
      type: [String, Number],
      default: ''
    },
    // 导出时文件名（如果使用iview的导出的话）
    exportFilename: {
      type: String,
      default: '表格数据'
    },
    // 导出时其他配置
    exportParams: {
      type: Object,
      default: () => { return {} }
    },
    // 是否禁用分页组件
    isDisabled: {
      type: Boolean,
      default: false
    },
    // 是否显示表头
    showHeader: {
      type: Boolean,
      default: true
    },
    // 表格数据（当父组件没有传递action时，表格的数据将交由该参数控制，不传它，可能表格初始数据为空）
    tableData: {
      type: Array,
      default: () => [{}]
    },
    // 分页总大小（当父组件没有传递action时，表格的数据将交由该参数控制，不传它，可能表格初始数据为空）
    tableTotal: {
      type: Number,
      default: 0
    },
    // 是否显示分页
    showSizer: {
      type: Boolean,
      default: true
    },
    // 是否显示总数
    showTotal: {
      type: Boolean,
      default: true
    },
    // 是否显示快梯
    showElevator: {
      type: Boolean,
      default: true
    },
    // 静态按钮（非权限按钮，而是模块表格中所有按钮，数组里面可以是一个对象也可以是一个字符串，如果是一个对象，对象中的属性可以是按钮的样式，但是对象的value和label属性必须存在，具体使用可以参照数据备份模块）
    publicBtn: {
      type: Array,
      default: () => { return ['update', 'delete', 'view'] }
    },
    // 是否自行处理分页数据处理，为true，当前组件将向父组件暴露处理分页的2个函数
    selfWithPage: {
      type: Boolean,
      default: false
    },
    // 父组件应该将搜索条件通过这个参数传递过来（不传可能造成分页与搜索条件无法同时使用）
    initParams: {
      type: Object,
      default: () => { return {} }
    },
    // 分页默认参数
    baseParams: {
      type: Object,
      default: () => { return { page: 'page', rows: 'rows' } }
    },
    // 表格是否加载（当父组件没有传递action时，表格的加载状态将交由该参数控制）
    isLoading: {
      type: Boolean,
      default: true
    },
    // 如果使用开关具名，该参数用于控制开关的值(后台返回的字段名)
    statusField: {
      type: String,
      default: 'store'
    },
    // 如果使用下拉菜单，该参数用于控制开关的值(后台返回的字段名)
    dropField: {
      type: String,
      default: 'activeStatus'
    },
    // 下拉菜单的值
    selectList: {
      type: Array,
      default: () => { return [] }
    },
    // 模块id的名字，不在当前组件删除的话，该值不需要传递
    idName: {
      type: String,
      default: ''
    },
    // 删除接口
    removeDataByKey: {
      type: String,
      default: ''
    },
    // 是否在本组件初始化发送请求，传递false可以取消第一次请求
    isInitRequest: {
      type: Boolean,
      default: true
    },
    // 是否显示分页
    isShowPage: {
      type: Boolean,
      default: true
    },
    // 控制更新按钮的额外参数，该值来源于当前行的某个字段
    updateBtnExtraParam: {
      type: [String, Boolean],
      default: false
    },
    // 控制更新按钮的额外参数，该值来源于当前行的某个字段的值
    updateBtnExtraVal: {
      type: [String, Number, Boolean],
      default: 1
    },
    // 分页查询是否需要默认值,既page和size
    isDefaultParams: {
      type: Boolean,
      default: true
    },
    // 分页查询使用的方法，默认为post
    requestM: {
      type: String,
      default: 'post'
    },
    // 如果使用开关具名，那么在开关触发前警告的标题
    switchBeforeTitle: {
      type: String,
      default: '你确定要进行该操作吗？'
    },
    // 如果使用开关具名，那么在开关触发前警告的内容
    switchBeforeContent: {
      type: String,
      default: ''
    }
  },
  data () {
    return {
      // 分页总大小
      total: 0,
      typeOf,
      current: 1,
      // 当用户传递了action，表格的加载状态交由该参数控制
      state: true,
      // 表格数据
      dataSource: [],
      // 获取表格数据基本参数（比如一页总数，当前页）
      defaultParams: {
        [this.baseParams.page]: 1,
        [this.baseParams.rows]: 10
      },
      requestParams: ''
    }
  },
  computed: {
    // 表格加载
    loading () {
      // 如果传了action，表示通过当前组件进行请求，加载将交由当前组件控制，反之交由父组件进行控制
      if (this.action) {
        return this.state
      }
      return this.isLoading
    },
    // 当前菜单的权限
    currRouteAuth () {
      const meta = this.$route.meta
      const btnAuthList = meta.btnAuthList || []
      // console.log(btnAuthList)
      return btnAuthList
    },
    // 更新按钮
    updateBtn () {
      return this.currRouteAuth.indexOf('修改') !== -1 && this.publicBtn.indexOf('update') !== -1
    },
    // 查看按钮
    selectBtn () {
      return this.currRouteAuth.indexOf('列表') !== -1 && this.publicBtn.indexOf('view') !== -1
    },
    // 删除按钮
    deleteBtn () {
      return this.currRouteAuth.indexOf('删除') !== -1 && this.publicBtn.indexOf('delete') !== -1
    },
    // 过滤查看、删除、更新按钮
    otherBtnList () {
      return this.currRouteAuth.filter(item => item !== '修改' && item !== '列表' && item !== '删除' && item !== '新增')
    },
    // 除查看、删除、更新外当前用户所拥有的按钮
    otherBtnAuthList () {
      let filterList = this.publicBtn.filter(item => this.otherBtnList.some(item1 => item === item1 || item.value === item1))
      filterList = filterList.map(item => {
        if (typeOf(item) === 'object') {
          return item
        } else {
          return {
            // 按钮类型
            type: 'text',
            // 按钮是否幽灵属性
            ghost: false,
            // 按钮大小
            size: 'small',
            // 按钮形状
            shape: '',
            // 按钮值，该值用于绑定点击时的类型
            value: item,
            // 按钮名称，用于显示按钮名字（）
            label: item,
            style: 'color: #0F74FD'
          }
        }
      })
      return filterList
    },
    // 开关按钮
    stateBtn () {
      return this.currRouteAuth.indexOf('状态') !== -1 && this.publicBtn.indexOf('status') !== -1
    },
    // 重置按钮（前一个判断的数据全有后台控制，后一个由前台控制）
    resetBtn () {
      return this.currRouteAuth.indexOf('重置') !== -1 && this.publicBtn.indexOf('reset') !== -1
    }
  },
  mounted () {
    /* 如果父组件传递了地址，那么我们就在当前组件中发送请求，反之父组件自己请求数据， */
    if (!this.action) {
      this.dataSource = this.tableData
      this.total = this.tableTotal
    } else if (this.isInitRequest) {
      this.getData()
    }
  },
  methods: {
    /**
     * 点击编辑
     * @param row 当前行数据
     * @param
     * @param index
     */
    handleUpdate (row) {
      // 交由父组件处理
      this.$emit('handleUpdate', row, 2)
    },
    /**
     * 查看
     */
    handleView (row) {
      // 交由父组件处理
      this.$emit('handleView', row, 3)
    },
    /**
     * 除删除、编辑、查看按钮，模块有的按钮都将触发该函数(如：下载)
     * type:标识当前按钮是下载或是其它按钮
     * row：当前行数据
     */
    handleExpand (type, row) {
      this.$emit('handle-expand', type, row)
    },
    /**
     * 点击删除时触发
     * @param row 当前行数据
     * @param index
     */
    handleRemove (row, index) {
      message.modal.confirm('你确定要删除吗？', '此次操作将删除<span style="color: red">1</span>条记录', () => {
        if (this.idName !== '' && this.removeDataByKey !== '') {
          deleteTableByPk(this.removeDataByKey, row[this.idName]).then((data) => {
            message.message.success(data.message)
            // 重新请求数据
            this.getData()
          })
        } else {
          // 用户确定删除后交由父组件处理
          this.$emit('handleRemove', { row, index })
        }
      }, () => {
        message.message.success('取消成功')
      })
    },
    /**
     * 更新表格及分页数据（如果传递了action既表示在本组件中获取表格数据，那么该方法使用不到）
     * 可通过ref的通讯方式调用该方法
     * @param list 表格数据
     * @param total 分页总大小
     */
    publicSelfUpdateData (list = [], total = 0) {
      if (this.action) {
        console.warn('方法使用错误')
      }
      this.dataSource = list
      this.total = total
    },
    /**
     * 获取表格数据
     * @param params 额外参数，比如搜索关键字
     * @param isSearch 是否是搜索按钮触发
     * @param defaultParams 基本参数，比如当前页等
     * @param initParams 该参数将由父组件进行传递
     */
    getData (params = '', isSearch = false, defaultParams = this.isDefaultParams ? this.defaultParams : {}, initParams = this.initParams) {
      this.requestParams = params
      // 判断搜索按钮
      if (isSearch) {
        const pageExpress = this.baseParams.page
        // 设置页码为1
        this.defaultParams[pageExpress] = 1
      }
      // 开启加载
      this.state = true
      // 请求数据
      getTableData(this.action, {
        ...defaultParams,
        ...initParams,
        ...params
      }, this.requestM, this.isDefaultParams).then(({ data }) => {
        if (typeOf(data) === 'object' || typeOf(data) === 'array') {
          // 表格数据
          this.dataSource = typeOf(data.list) === 'array' && data.list.length > 0 ? data.list : typeOf(data) === 'array' ? data : []
          this.current = data.pageNum && data.pageNum > 0 ? data.pageNum : 1
          this.total = data.total
        } else {
          this.dataSource = []
          this.total = 0
          this.current = 1
        }
        // 关闭加载
        this.state = false
      }).catch(error => {
        message.message.error(error.message ? error.message : '查询出错,请检查后重试或者联系管理员')
        this.state = false
        throw new Error(error)
      })
    },
    /**
     * 页码改变的回调，返回改变后的页码
     * @param page
     */
    handleChange (page) {
      const pageExpress = this.baseParams.page
      this.defaultParams[pageExpress] = page
      if (this.selfWithPage) {
        this.$emit('handle-change-page', page)
      } else {
        this.getData(this.requestParams)
      }
    },
    /**
     * 切换每页条数时的回调，返回切换后的每页条数
     * @param rows
     */
    handelSizeChange (rows) {
      const rowsExpress = this.baseParams.rows
      this.defaultParams[rowsExpress] = rows
      if (this.selfWithPage) {
        this.$emit('handle-change-rows', rows)
      } else {
        this.getData(this.requestParams)
      }
    },
    /**
     * 开关状态发生变化前触发（iview4新增，小于该版本请升级后使用）
     */
    handleBeforeChange () {
      return new Promise(resolve => {
        message.modal.confirm(this.switchBeforeTitle, this.switchBeforeContent, () => {
          resolve()
        })
      })
    },
    /**
     * 开关状态发送变化时触发
     * @param state
     */
    onChange (state, row) {
      this.$emit('handle-change-switch', { state, row })
    },
    /**
     * 如果表格有多选功能，选项发生变化时触发
     * @param selection
     */
    handleSelectionChange (selection) {
      // 交由父组件处理
      this.$emit('handleSelectionChange', selection)
    },
    /**
     * 导出表格数据
     */
    publicExportData () {
      this.$refs.table.exportCsv({
        filename: this.exportFilename,
        ...this.exportParams
      })
    },
    /**
     * 点击下拉时触发
     * @param name
     */
    handleClickDrop (name, row) {
      this.$emit('handle-click-drop', name, row)
    }
  }
}
</script>

<style scoped lang="scss">
.table{
  width: auto;
  height: auto;
  .ivu-btn-text{
    width: auto;
    padding: 0;
    border: none;
    margin: 0 20px 0 0;
    &:hover{
      background-color: transparent;
    }
  }
  .page{
    margin-top: 20px;
    text-align: right;
  }
}
</style>
